#include "Model.h"

#include <iostream>

namespace Server {

Model::Model() {
    int num;
    int id;

    data_ = new QFile("users.dat");
    data_->open(QIODevice::ReadOnly);
    QDataStream userStream(data_);
    userStream >> num;
    for(int i = 0; i < num; ++i){
        User user;
        userStream >> id;
        user.setID(id);
        userStream >> user.owned_;
        users_.push_back(user);
		std::cout << "Wczytano usera: " << user.getID() << "\n";
    }
	data_->close();

    data_ = new QFile("files.dat");
    data_->open(QIODevice::ReadOnly);
    QDataStream fileStream(data_);
	QByteArray insertHash;

    fileStream >> num;
    for(int i = 0; i < num; i++){
        FileDesc file;
        fileStream >> file.fname;
        fileStream >> file.hash;
        fileStream >> file.size;
        fileStream >> id;
        file.type = (Common::FileType)id;
        fileStream >> file.owners;
        file.total_seeds = file.owners.count();
        file.active_seeds = 0;
		insertHash = file.hash;
		insertHash = insertHash.append((char *)&(file.size), 4);
		files_.insert(insertHash, file);
    }
	data_->close();

}

Model::~Model() {
	saveAll();
}

void Model::saveAll() {

	data_ = new QFile("users.dat");
	data_->open(QIODevice::WriteOnly);
	QDataStream userStream(data_);
	userStream << users_.count();
	foreach(User user, users_) {
		userStream << user.getID();
		userStream << user.owned_;
	}
	data_->close();

	data_ = new QFile("files.dat");
	data_->open(QIODevice::WriteOnly);
	QDataStream fileStream(data_);
	fileStream << files_.count();
	foreach(FileDesc file, files_){
		fileStream << file.fname;
		fileStream << file.hash;
		fileStream << file.size;
		fileStream << file.type;
		fileStream << file.owners;
	}
	data_->close();
}

void Model::loginClient(int id) {
	Q_UNUSED(id);
//    if(findUser(id) == -1){
//        id = registerUser();
//    }
//    //Dodaje usera do listy aktywnych
//	//User user = users_[users_.indexOf(id)];
//    activeUsers_.push_back(user);
//
//    ///Przechodzę po liscie plikuw usera i zgłaszam, ze seeduję
//    foreach(/*FileDesc*/QByteArray file, user.owned_){
//        QMap<QByteArray, FileDesc>::Iterator iter = files_.find(file);//.hash);
//        if(iter != files_.end())
//            iter.value().active_seeds++;
//    }
}

void Model::logoutClient(int id) {
	Q_UNUSED(id);
//    int toRmv = findUser(id, true);
//    User user = users_.at(id);
//    ///Przechodzi listę plików usera i zmniejsza liczbę seedów
//    foreach(/*FileDesc*/QByteArray file, user.owned_){
//        QMap<QByteArray, FileDesc>::Iterator iter = files_.find(file);//.hash);
//        if(iter != files_.end())
//            iter.value().active_seeds--;
//    }
//    ///Usuwa usera z listy aktywnych
//    activeUsers_.removeAt(toRmv);
}

int Model::findUser(int id, bool active) {
    User usr;

	std::cout << "Model - szukam usera " << id << "\n";

    if(!active)

		foreach(usr, users_) {
            if(usr.getID() == id)
                return id;
        }

    else

		foreach(usr, activeUsers_) {
            if(usr.getID() == id)
                return activeUsers_.indexOf(usr);
        }

    return -1;
}

int Model::registerUser() {
    User nowy;
    int id;

    ///Dodaje noweg usera do listy i nadaje mu ID
    users_.push_back(nowy);
    id = users_.count();
    users_.back().setID(id);

    return id;
}

bool Model::addFile(QString fname, int size, QByteArray hash, Common::FileType type, int client_id) {
	QByteArray insertHash =  hash;
	insertHash = insertHash.append((char *)&size, 4);
    FileDesc *file;
    ///Sprawdzam czy plik istnieje w bazie
    if(files_.contains(insertHash)){
		file = &files_.find(insertHash).value();
        ///Dodaje ewentualne inne nazwy
        if(!file->fname.contains(fname))
            file->fname.push_back(fname);

        // ewentualne dodanie dodatkowych rozmiarów, trzeba przedyskutować

        ///Dodaje usera do listy posiadaczy
        file->owners.push_back(client_id);
        file->total_seeds++;
        file->active_seeds++;
        return false;
    }
    else{
        ///Tworze nowy plik w bazie
        file = new FileDesc;
        file->fname.push_back(fname);
        file->hash = hash;
        file->size = size;
        file->type = type;
        file->total_seeds = 1;
        file->active_seeds = 1;
        file->owners.push_back(client_id);
        files_.insert(insertHash, *file);
        return true;
    }
}

bool Model::removeFile(QString fname, int size, QByteArray hash, int client_id) {

	Q_UNUSED(fname);

    ///Sprawdzam czy plik istnieje
    FileDesc *file;
    hash.append((char *)&size);
    if(files_.contains(hash)){
         file = &files_.find(hash).value();
        //Jesli jestem jedynym użytkownikiem to usuwam plik z bazy
        if(file->total_seeds == 1){
            if(files_.remove(hash))
                return true;
        }
        ///Zmniejszam liczbę seedów i usuwam posiadacza pliku
        file->total_seeds--;
        file->active_seeds--;
        file->owners.remove(file->owners.indexOf(client_id));
        return false;
	} else throw("No such hash in base");
}

const QVector<FileDesc> Model::find(QString query, Common::FileType type, int size_min, int size_max) {
	QVector<FileDesc> v;


	foreach(FileDesc fd, files_) {
		foreach (QString str, fd.fname)
			if (str.contains(query, Qt::CaseInsensitive)) {
				if ( (type != Common::ftAny) && (fd.type != type) )
					continue;
				if ( (size_min >=0) && (fd.size < size_min) )
					continue;
				if ( (size_max >=0) && (fd.size > size_max) )
					continue;

				v.push_back(fd);
				break;
			}
	}

	/*
	QRegExp regex(query);
	QStringList zapytania = regex.capturedTexts();
	foreach(QString name, zapytania){
		foreach(FileDesc file, files_){
			if(file.fname.contains(name) &&
			   file.type == type &&
			   file.size >= size_min &&
			   file.size <= size_max)
				v.push_back(file);
		}
	}*/

	return v;
}

const QVector<int> Model::findSeeds(int size, QByteArray hash) {
	QVector<int> v;
	hash = hash.append((char*)&size, 4);

	if (files_.find(hash) == files_.end())
		return v;

	foreach(int user, files_.find(hash).value().owners){
		User tmp;
		tmp.setID(user);
		// wyrzucamy wszystkich dawców, kontroler sprawdzi który z nich jest aktywny
		//if(activeUsers_.contains(tmp))
		v.push_back(user);
	}
	return v;
}

User::User() {
}

/*QList<FileDesc> User::getOwnedFiles(){
    return owned_;
}*/

QString User::getHost() {
    return host_;
}

void User::addFile(/*FileDesc*/QByteArray &file) {
    owned_.push_back(file);
}

void User::setHost(QString &host) {
    host_ = host;
}

void User::setID(int id) {
    id_ = id;
}

int User::getID() {
    return id_;
}

bool User::operator==(const User &s) const {
    return s.id_ == id_;
}

} //namespace Server

/*
  QDataStream &QDataStream::operator>>(qint8 &i)
{
    i = 0;
    CHECK_STREAM_PRECOND(*this)
    char c;
    if (!dev->getChar(&c))
        setStatus(ReadPastEnd);
    else
        i = qint8(c);
    return *this;
}

QDataStream &QDataStream::operator<<(qint32 i)
{
    CHECK_STREAM_PRECOND(*this)
    if (noswap) {
        dev->write((char *)&i, sizeof(qint32));
    } else {                                        // swap bytes
        register uchar *p = (uchar *)(&i);
        char b[4];
        b[3] = *p++;
        b[2] = *p++;
        b[1] = *p++;
        b[0] = *p;
        dev->write(b, 4);
    }
    return *this;
}
 */
